home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-68k-src / machines / amiga68k / libsrc / fd2lib.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  26KB  |  1,002 lines

  1. /*  fd2lib  by Volker Barthelmann                         */
  2. /*  rework 09/96 by Johnny Teveßen <j.tevessen@line.org>  */
  3. /*  V1.4 14-Jul-98 phx: ##abi support.                    */ 
  4. /*  V1.5 04-Oct-98 phx: FPU register support.             */
  5. /*                      Allow function names > 28 chars.  */
  6.  
  7. #define NDEBUG
  8.  
  9. #ifdef _DCC
  10. #  define CTYPE_NEAR
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <stdarg.h>
  18.  
  19. /* AmigaOS version string. Doesn't hurt... */
  20. const char VersTag[] = "\0$VER: fd2lib 1.5 (04.10.98)";
  21.  
  22. char *clibname,*clibtext;
  23.  
  24. #define MAXLINELEN       1000
  25. #define BUFFEREDLEN     16384   /* 1024 is standard */
  26.  
  27. #define NUMREGS        24
  28.  
  29. static const char *regnames[NUMREGS] =
  30. {
  31.   "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
  32.   "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
  33.   "fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7"
  34. };
  35.  
  36. enum
  37. {
  38.   A0=0, A1, A2, A3, A4, A5, A6, A7,
  39.   D0  , D1, D2, D3, D4, D5, D6, D7,
  40.   FP0 ,FP1,FP2,FP3,FP4,FP5,FP6,FP7
  41. };
  42.  
  43. #define SMALLCODE        1
  44. #define SMALLDATA        2
  45. #define FASTCALL         4
  46. #define NEWNOTATE        8
  47. #define VARGSLOGIC      16
  48. #define DEBUG           32
  49.  
  50. #ifndef   TRUE
  51.    typedef short BOOL;
  52. #  define TRUE  1
  53. #  define FALSE 0
  54. #endif
  55.  
  56. #ifndef   NULL
  57. #  define NULL ((void *)0L)
  58. #endif
  59.  
  60. #ifdef __GNUC__
  61. #  define gnuspec(x) x
  62. #else
  63. #  define gnuspec(x)
  64. #endif
  65.  
  66. #define NORETURN gnuspec(__attribute__ ((noreturn)))
  67.  
  68.  
  69. static const char *varargs[] =
  70. {
  71. #include "vargs.h"
  72.   NULL, NULL
  73. };
  74.  
  75.  
  76.  
  77. int get_type(char *dest,const char *p,const char *fname,int arg)
  78. {
  79.   int nest,carg,l=strlen(fname);const char *last=p,*m,*m2;
  80.   if(arg<0) return 0;
  81.   while(*p){
  82.     if(*p==';'||*p=='\n')
  83.       {last=p;while(isspace((unsigned char)*last)) last++;}
  84.     if(!strncmp(p,fname,l)){
  85.       m=p;m2=p-1;p+=l;
  86.       while(isspace((unsigned char)*p)) p++;
  87.       if(*p!='('||isalnum((unsigned char)*m2)){
  88.         continue;
  89.       }else{
  90.         if(arg==0){
  91.           memcpy(dest,last,m-last);
  92.           dest[m-last]=0;
  93.           return 1;
  94.         }
  95.         p++;carg=1;nest=0;
  96.         while(1){
  97.           while(isspace((unsigned char)*p)) p++;
  98.           if(*p==')'||*p==0)
  99.             return 0;
  100.           if(carg==arg){
  101.             while(nest!=0||(*p!=','&&*p!=')')){
  102.               if(!*p) return 0;
  103.               if(*p=='(') nest++;
  104.               if(*p==')') nest--;
  105.               *dest++=*p++;
  106.             }
  107.             *dest=0;
  108.             return 1;
  109.           }
  110.           while(nest!=0||(*p!=','&&*p!=')')){
  111.             if(!*p) return 0;
  112.             if(*p=='(') nest++;
  113.             if(*p==')') nest--;
  114.             p++;
  115.           }
  116.           p++;
  117.           carg++;
  118.         }
  119.       }
  120.     }
  121.     p++;
  122.   }
  123.   return 0;
  124. }
  125.  
  126.  
  127. static void ExitFailure(const char *, const char *) NORETURN;
  128.  
  129.  
  130. static void ExitFailure(const char *cause, const char *insertme)
  131. {
  132.   fprintf(stderr, cause, insertme);
  133.  
  134.   exit(EXIT_FAILURE);
  135. }
  136.  
  137.  
  138. static void check(const char *ptr)
  139. {
  140.   if(!*ptr)
  141.   {
  142.     ExitFailure("Unexpected EOL\n", NULL);
  143.   }
  144. }
  145.  
  146.  
  147. static void warnhim(int linenr, const char *format, ...) gnuspec(__attribute__ ((format (printf, 2, 3))));
  148.  
  149.  
  150. static void warnhim(int linenr, const char *format, ...)
  151. {
  152.   char linebuf[250];
  153.   va_list vl;
  154.  
  155.   va_start(vl,format);
  156.   vsprintf(linebuf, format, vl);
  157.   va_end(vl);
  158.  
  159.   fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
  160. }
  161.  
  162.  
  163. static FILE *OpenLVO(const char *name, const char *outdir,
  164.                      const char *outform)
  165. {
  166.   FILE *lvos;
  167.   char lvoname[MAXLINELEN];
  168.  
  169.   strcpy(lvoname, outdir);
  170.  
  171.   if(name)
  172.   {
  173.     char *k = (char *)name, *p;
  174.     int lvonamlen;
  175.  
  176.     if((p = strrchr(k, '/')) != NULL) k = p + 1;
  177.     if((p = strrchr(k, ':')) != NULL) k = p + 1;
  178.  
  179.     strcat(lvoname, k);
  180.  
  181.     lvonamlen = strlen(lvoname);
  182.  
  183.     if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
  184.     {
  185.       lvoname[lvonamlen-7] = '\0';
  186.     }
  187.     else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
  188.     {
  189.       lvoname[lvonamlen-3] = '\0';
  190.     }
  191.  
  192.     strcat(lvoname, "_lvo.s");
  193.   }
  194.   else
  195.   {
  196.     strcat(lvoname, "fd_lvo.s");
  197.   }
  198.  
  199.   printf(outform, lvoname, lvoname, lvoname);
  200.  
  201.   lvos = fopen(lvoname, "w");
  202.  
  203.   return(lvos);
  204. }
  205.  
  206.  
  207. static void ProcessFD(const char *name, int mode,
  208.                       const char *outdir, const char *outform)
  209. {
  210.   FILE *fd, *lvos;
  211.   FILE *out;
  212.   int offset = 0, i, j, count, savecount, fsavecount;
  213.   char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
  214.   char line[MAXLINELEN], lastchar='A';
  215.   register char *p;
  216.   char *functionp;
  217.   int reg[NUMREGS], loops, linenr = 0;
  218.   BOOL public = -1;           /* Why FALSE? */
  219.   BOOL abim68k = TRUE;
  220.   BOOL fpregs;
  221.   char typ[1024];
  222.  
  223.   /*  "-1" is the initial value for "public". It means:
  224.   **  no statement yet.
  225.   */
  226.  
  227.   *function = *base = *line = '\0';
  228.  
  229.   if(name) fd = fopen(name, "r");
  230.   else     fd = stdin;
  231.  
  232.   if(!fd) ExitFailure("Could not open `%s'\n", name);
  233.  
  234.   setvbuf(fd, NULL, _IOFBF, BUFFEREDLEN);             /* maybe _IOLBF? */
  235.  
  236.   if(!(lvos = OpenLVO(name, outdir, outform)))
  237.     ExitFailure("Could not create lvo file\n", NULL);
  238.  
  239.   setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
  240.  
  241.   for(;;)
  242.   {
  243.     char *k;
  244.  
  245.     if(!fgets(line, MAXLINELEN-1, fd)) ExitFailure("Unexpected EOF\n", NULL);
  246.  
  247.     linenr ++;
  248.  
  249.     if((*line == '*') || !*line) continue;
  250.  
  251.     switch(*line + line[2]) {
  252.       case ('#'+'a'):
  253.         if (!strncmp(line, "##abi", 5)) {               /* ##abi */
  254.           p = line+5;
  255.           while (isspace((unsigned)*p)) p++;
  256.           if (!strncmp(p, "M68k", 4)) {
  257.             abim68k = TRUE;
  258.             if(mode & DEBUG)
  259.               printf("ABI set to M68k\n");
  260.           }
  261.           else if (!strncmp(p, "PPC", 3)) {
  262.             abim68k = FALSE;
  263.             if(mode & DEBUG)
  264.               printf("ABI set to PPC (WarpOS)\n");
  265.           }
  266.           else
  267.             warnhim(linenr, "Unknown ##abi specification ignored!");
  268.           continue;
  269.         }
  270.         break;
  271.  
  272.       case ('#'+'b'):
  273.         if(!strncmp(line, "##base", 6)) {
  274.           if(*base) warnhim(linenr, "##base detected more than once!");
  275.  
  276.           p = line+6; while(isspace(*p)) p++;
  277.           k = base  ; while(isgraph(*p)) *k++ = *p++;
  278.  
  279.           *k = '\0';
  280.  
  281.           if(mode & DEBUG) printf("Base set to `%s'\n", base);
  282.           continue;
  283.         }
  284.  
  285.         if(!strncmp(line, "##bias", 6)) {
  286.           p = line+6; while(isspace(*p)) p++;
  287.           sscanf(p, "%i", &offset);
  288.  
  289.           if(mode & DEBUG) printf("Bias set to -%d\n", offset);
  290.           continue;
  291.         }
  292.         break;
  293.  
  294.       case ('#'+'p'):
  295.         if(!strncmp(line, "##public", 8)) {
  296.           if(public == TRUE)  warnhim(linenr, "##public after ##public detected!");
  297.           else                public = TRUE;
  298.  
  299.           if(mode & DEBUG) printf("Turned on public mode at bias -%d\n", offset);
  300.           continue;
  301.         }
  302.  
  303.         if(!strncmp(line, "##private", 9)) {
  304.           if(public == FALSE) warnhim(linenr, "##private after ##private detected!");
  305.           else                public = FALSE;
  306.  
  307.           if(mode & DEBUG) printf("Turned off public mode at bias -%d\n", offset);
  308.           continue;
  309.         }
  310.         break;
  311.  
  312.       case ('#'+'e'):
  313.         if(!strncmp(line, "##end", 5)) return;
  314.         break;
  315.     }
  316.  
  317.     if(*line == '#') {
  318.       warnhim(linenr, "Unknown directive: `%s'!", line);
  319.       continue;
  320.     }
  321.  
  322.     if(!public || !abim68k) {
  323.       offset += 6;
  324.       continue;
  325.     }
  326.  
  327.     if(public == -1) {
  328.       warnhim(linenr, "Neither ##public nor ##private specified yet. Assuming ##public.");
  329.       public = TRUE;
  330.     }
  331.  
  332.     functionp = function;
  333.  
  334.     for(loops=0; loops<=1; loops++) {
  335.       int saveoffset;
  336.       char *p = line; char *k = functionp;
  337.  
  338.       while(isspace(*p)) p++;
  339.  
  340.       if(!loops)
  341.       {
  342.         while((*p != '(') && *p) *k++ = *p++;
  343.  
  344.         check(p);
  345.         *k = '\0';
  346.  
  347.         fprintf(lvos, "_LVO%s\tequ\t-%d\n"
  348.                       "\txdef\t_LVO%s\n",
  349.                       functionp, offset, functionp);
  350.       }
  351.       else
  352.       {
  353.         while((*p != '(') && *p) p++;
  354.         check(p);
  355.       }
  356.  
  357.       if(mode & DEBUG)
  358.         printf("function=%s, loops=%d\n", functionp, loops);
  359.  
  360.       /* This should be AMIGA OS only: */
  361.       if (strlen(functionp) > 28) {
  362.         sprintf(ff, "%s%.27s%c.s", outdir, functionp, lastchar);
  363.         warnhim(linenr,"File name %s.s is too long for AmigaOS file system."
  364.                 " Changed into: %.27s%c.s",functionp,functionp,lastchar);
  365.         if (lastchar=='Z')
  366.           lastchar = 'A';
  367.         else
  368.           lastchar++;
  369.       }
  370.       else
  371.         sprintf(ff, "%s%s.s", outdir, functionp);
  372.  
  373.       /* Open function stub source file */
  374.  
  375.       printf(outform, ff, ff, ff);
  376.       out = fopen(ff, "w");
  377.  
  378.       if(!out) ExitFailure("Could not create <%s>\n", functionp);
  379.       setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
  380.  
  381.       /* Set all registers to 'unused' */
  382.       for(i=0; i<NUMREGS; i++) reg[i] = 0;
  383.  
  384.       /* Skip argument names */
  385.       while((*p!=')') && *p) p++;
  386.  
  387.       check(p);
  388.       p++;
  389.  
  390.       if(clibtext&&!loops){
  391.         if(!get_type(typ,clibtext,functionp,0)) strcpy(typ,"error");
  392.         printf("%s __%s(",typ,functionp);
  393.       }
  394.  
  395.       /* Search for beginning of register list */
  396.  
  397.       while((*p!='(') && *p) p++;
  398.  
  399.       check(p);
  400.       p++;
  401.  
  402.       /* Scan register list */
  403.       count = savecount = fsavecount = 0;
  404.       fpregs = FALSE;
  405.  
  406.       while((*p!=')') && *p) {
  407.         char c = *p;
  408.  
  409.         /* Check whether register description is valid */
  410.         if (!((c=='a' || c=='A' || c=='d' || c=='D') &&
  411.               (p[1]>='0' && p[1]<='7')) &&
  412.             !((c=='f' || c=='F') && (p[1]=='p' || p[1]=='P') &&
  413.               (p[2]>='0' && p[2]<='7')))
  414.             ExitFailure("Bad register description\n", NULL);
  415.  
  416.         /* Convert description to internal enum format */
  417.         /* Corrected: 'A' was not recognized           */
  418.         if (c=='a' || c=='A')
  419.           j = p[1] - '0';
  420.         else if (c=='d' || c=='D')
  421.           j = p[1] - ('0'-8);
  422.         else
  423.           j = p[2] - ('0'-16);
  424.  
  425.         if(clibtext&&!loops){
  426.           if(!get_type(typ,clibtext,functionp,count+1)) strcpy(typ,"error");
  427.           printf("__reg(\"%s\") %s,",regnames[j],typ);
  428.         }
  429.  
  430.         /* Mark register as used and save its argument counter */
  431.  
  432.         reg[j] = ++count;
  433.  
  434.         /* Increase counter if register has to be saved */
  435.  
  436.         if (j>=FP0) {
  437.           if (j>=FP2 && j<=FP7)
  438.           fsavecount++;
  439.         }
  440.         else if (!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
  441.           savecount++;
  442.  
  443.         /* Search for next register */
  444.         if (j >= FP0) {
  445.           fpregs = TRUE;
  446.           p += 3;
  447.         }
  448.         else
  449.           p += 2;
  450.         while(isspace(*p) && *p)     p++;
  451.  
  452.         if((*p == '/') || (*p==',')) p++;
  453.         else if(*p != ')') ExitFailure("Parse error - ')' expected\n", NULL);
  454.  
  455.         while(isspace(*p) && *p)     p++;
  456.         check(p);
  457.       }
  458.  
  459.       /* Write assembler headers */
  460.       if (fpregs) fprintf(out,"\tfpu\t1\n");
  461.       if (mode & SMALLDATA) fprintf(out, "\tnear\t%s,-2\n", regnames[A4]);
  462.       if (mode & SMALLCODE) fputs  (     "\tnear\tcode\n" , out);
  463.  
  464.       if (*base) fprintf(out, "\txref\t%s\n", base);
  465.  
  466.       fprintf(out, "\txdef\t_%s\n"
  467.                    "\tsection\t\"CODE\",code\n"
  468.                    "\n"
  469.                    "_%s:\n",
  470.                    functionp, functionp);
  471.  
  472.       if(clibtext&&!loops){
  473.         int i;
  474.         printf("__reg(\"a6\") void *)=\"\\tjsr\\t-%d(a6)\";\n",offset);
  475.         printf("#define %s(",functionp);
  476.         for(i=1;i<=count;i++){
  477.           if(i>1) printf(",");
  478.           printf("x%d",i);
  479.         }
  480.         printf(") __%s(",functionp);
  481.         for(i=1;i<=count;i++) printf("(x%d),",i);
  482.         printf("%s)\n",base+1);
  483.       }
  484.  
  485.       if (fsavecount) {
  486.         char c = '\t';
  487.         /* number of FPU registers to be saved */
  488.  
  489.         if (!(mode & FASTCALL) && (fsavecount > 1))
  490.           fprintf(out,"\tfmovem");
  491.  
  492.         for (i=FP2; i<=FP7; i++) {
  493.           if (reg[i]) {
  494.             if ((mode & FASTCALL) || (fsavecount == 1)) {
  495.               fprintf(out,"\tfmove.x\t%s,-(%s)\n",
  496.                       regnames[i],regnames[A7]);
  497.             }
  498.             else {
  499.               fprintf(out,"%c%s",c,regnames[i]);
  500.               c = '/';
  501.             }
  502.           }
  503.         }
  504.         if (!(mode & FASTCALL) && (fsavecount > 1))
  505.           fprintf(out,",-(%s)\n",regnames[A7]);
  506.       }
  507.  
  508.       if(savecount) {
  509.         /* 'savecount' registers have to be saved */
  510.  
  511.         /* Always save library register */
  512.  
  513.         if((mode & FASTCALL) || (savecount == 1))
  514.         {
  515.           /*  Store registers sequential. NEW: Changed that it'll also be
  516.           **  used if only two (including library register) registers have
  517.           **  to be stored. That's faster than the original method.
  518.           */
  519.  
  520.           fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
  521.         }
  522.         else
  523.         {
  524.           /*  It would be better to set A6 to the end of the list ...
  525.           */
  526.  
  527.           fprintf(out, "\tmovem.l\t%s", regnames[A6]);
  528.         }
  529.  
  530.         for(i=A2; i<=D7; i++) {
  531.           /* Can start at 2, because 0 and 1 are ignored */
  532.           if(reg[i] != 0)
  533.           {
  534.             switch(i)
  535.             {
  536.               case D0:
  537.               case D1:
  538.                 break;
  539.  
  540.               case A6:
  541.                 warnhim(linenr, "Register conflict in `%s' "
  542.                         "(using libbasereg)!", functionp);
  543.                 break;
  544.  
  545.               default:
  546.                 if((mode & FASTCALL) || (savecount == 1))
  547.                 {
  548.                   fprintf(out, "\tmove.l\t%s,-(%s)\n",
  549.                           regnames[i], regnames[A7]);
  550.                 }
  551.                 else
  552.                 {
  553.                   fprintf(out, "/%s", regnames[i]);
  554.                 }
  555.                 break;
  556.             }
  557.           }
  558.         }
  559.  
  560.         if(!((mode & FASTCALL) || (savecount == 1)))
  561.             fprintf(out, ",-(%s)\n", regnames[A7]);
  562.       }
  563.       else
  564.       {
  565.          /*  No registers have to be saved, so just save the register
  566.          **  where the library base will be stored
  567.          */
  568.          fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
  569.       }
  570.  
  571.       /* Load A6 with base NOW, so there's no conflict with SMALLDATA and A4 anymore ... */
  572.  
  573.       if(*base != '\0')
  574.       {
  575.         if(mode & SMALLDATA)
  576.         {
  577.           fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%s,%s),%s\n"
  578.                                           : "\tmove.l\t%s(%s),%s\n",
  579.                        base, regnames[A4], regnames[A6]);
  580.         }
  581.         else
  582.         {
  583.           fprintf(out, "\tmove.l\t%s,%s\n", base, regnames[A6]);
  584.         }
  585.       }
  586.       else ExitFailure("No base defined!\n", NULL);
  587.  
  588.       saveoffset = ((savecount+2)<<2) + fsavecount*12;
  589.  
  590.       for(j=1; j<=count; j++)    /* Arguments */
  591.       {
  592.         for(i=0; i<NUMREGS; i++) /* Registers */
  593.         {
  594.           if(reg[i] == j)     /* Argument in THIS register? */
  595.           {
  596.  
  597.             if (i >= FP0) {
  598.               /* FPU registers fp0-fp7 */
  599.  
  600.               fprintf(out,(mode & NEWNOTATE) ?
  601.                       "\tfmove.d\t(%d,%s),%s\n" : "\tfmove.d\t%d(%s),%s\n",
  602.                       saveoffset, regnames[A7], regnames[i]);
  603.               saveoffset += 8;
  604.             }
  605.  
  606.             else {
  607.               /* a0-a5 / d0-d7 */
  608.  
  609.               if ((i>=D7) || (reg[i+1] != j+1)
  610.                   || ((loops==1) && (j>=count-1))) {
  611.                 if(!loops || (j<count)) {
  612.                   fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%d,%s),%s\n"
  613.                                                   : "\tmove.l\t%d(%s),%s\n",
  614.                           saveoffset, regnames[A7], regnames[i]);
  615.                 }
  616.  
  617.                 else {
  618.                   /* Varargs */
  619.                   if(i <= 7) {
  620.                     /*  adress register */
  621.                     fprintf(out, (mode & NEWNOTATE) ? "\tlea\t(%d,%s),%s\n"
  622.                                                     : "\tlea\t%d(%s),%s\n",
  623.                                  saveoffset, regnames[A7], regnames[i]);
  624.                   }
  625.                   else {
  626.                     /*  data register  */
  627.  
  628.                     /*  Changed: moveq.l will be forced if possible
  629.                     **  (there are still assemblers that do not do this
  630.                     **  automatically).
  631.                     */
  632.                     fprintf(out, "\tmove%s\t#%d,%s\n" \
  633.                                  "\tadd.l\t%s,%s\n",
  634.                                  (saveoffset <= 127) ? "q" : ".l",
  635.                                  saveoffset, regnames[i],
  636.                                  regnames[A7], regnames[i]);
  637.                   }
  638.                 }
  639.               }
  640.               else {
  641.                 /* Here no fastcall - slower. :-( */
  642.   
  643.                 fprintf(out, (mode & NEWNOTATE) ? "\tmovem.l\t(%d,%s),%s"
  644.                                                 : "\tmovem.l\t%d(%s),%s",
  645.                              saveoffset, regnames[A7], regnames[i]);
  646.   
  647.                 while ((i<D7) && (reg[i+1] == j+1)
  648.                        && (!loops || (j<count-1))) {
  649.                   i++; j++;
  650.                   fprintf(out, "/%s", regnames[i]);
  651.                   saveoffset += 4;
  652.                 }
  653.                 fputc('\n', out);
  654.               }
  655.  
  656.               saveoffset += 4;
  657.             } /* if FPU regs */
  658.  
  659.           } /* if reg[i]==j */
  660.         } /* for i */
  661.       } /* for j */
  662.  
  663.       /* Now place the real function call */
  664.  
  665.       fprintf(out, (mode & NEWNOTATE) ? "\tjsr\t(-%d,%s)\n"
  666.                                       : "\tjsr\t-%d(%s)\n",
  667.                    offset, regnames[A6]);
  668.  
  669.       /* Start restoring registers ... libbasereg first. */
  670.  
  671.       if(!((mode & FASTCALL) || (savecount == 1)))
  672.       {
  673.         if(!savecount) fprintf(out, "\tmove.l\t(%s)+,%s" , regnames[A7], regnames[A6]);
  674.         else           fprintf(out, "\tmovem.l\t(%s)+,%s", regnames[A7], regnames[A6]);
  675.       }
  676.  
  677.       /* Now the others */
  678.  
  679.       for(i=A2; i<=D7; i++)
  680.       {
  681.         if((mode & FASTCALL) || (savecount == 1))
  682.         {
  683.           j = (D7+2) - i;   /* swap direction; okay for != 16 regs? */
  684.         }
  685.         else
  686.         {
  687.           j = i;
  688.         }
  689.  
  690.         if(reg[j])
  691.         {
  692.           switch(j)
  693.           {
  694.             case A6:
  695.             case D0:
  696.             case D1:
  697.               break;
  698.  
  699.             default:
  700.               if((mode & FASTCALL) || (savecount == 1))
  701.                 fprintf(out, "\tmove.l\t(%s)+,%s\n",
  702.                         regnames[A7], regnames[j]);
  703.               else
  704.                 fprintf(out, "/%s", regnames[j]);
  705.               break;
  706.           }
  707.         }
  708.       }
  709.  
  710.       /* If fastcall was used, a6 was put first. So we pop it last. */
  711.  
  712.       if((mode & FASTCALL) || (savecount == 1))
  713.       {
  714.         fprintf(out, "\tmove.l\t(%s)+,%s", regnames[A7], regnames[A6]);
  715.       }
  716.  
  717.       if (fsavecount) {
  718.         char c = ',';
  719.         /* number of FPU registers to be saved */
  720.  
  721.         if (!(mode & FASTCALL) && (fsavecount > 1))
  722.           fprintf(out,"\n\tfmovem\t(%s)+",regnames[A7]);
  723.  
  724.         for (i=FP2; i<=FP7; i++) {
  725.           if (reg[i]) {
  726.             if ((mode & FASTCALL) || (fsavecount == 1)) {
  727.               fprintf(out,"\n\tfmove.x\t(%s)+,%s",
  728.                       regnames[A7],regnames[i]);
  729.             }
  730.             else {
  731.               fprintf(out,"%c%s",c,regnames[i]);
  732.               c = '/';
  733.             }
  734.           }
  735.         }
  736.       }
  737.  
  738.  
  739.       /* Return from subroutine */
  740.       fputs("\n\trts\n\n\tend\n",out);
  741.  
  742.       fclose(out);
  743.  
  744.       if(loops != 0) break;
  745.  
  746.       p = (char *) *varargs;
  747.       loops = 3;
  748.  
  749.       if(mode & DEBUG) printf("Searching function `%s' in vargs table...\n", functionp);
  750.  
  751.       if(p != NULL)
  752.       {
  753.         if(mode & VARGSLOGIC)
  754.         {
  755.           int fnlen = strlen(functionp);
  756.  
  757.           if((fnlen > 7) && (!strcmp(functionp + fnlen - 7, "TagList")))
  758.           {
  759.             /*  xxxTagList function found. Make xxxTags of it
  760.             */
  761.  
  762.             strncpy(tmpfuncnam, functionp, fnlen - 4);
  763.             strcpy (tmpfuncnam + fnlen - 4,    "s"  );
  764.  
  765.             functionp = tmpfuncnam;
  766.             loops     = 0;
  767.           }
  768.           else if((fnlen > 1) && ((functionp[fnlen-1] == 'A') && (functionp[fnlen-2] >= 'a') && (functionp[fnlen-2] <= 'z')))
  769.           {
  770.             /*  Not that smart recognition... But you probably
  771.             **  don't want to have a function CreateDA() varargs,
  772.             **  want you?
  773.             **
  774.             **  Recognized are functions that end with 'A' and that
  775.             **  have a lowercase letter before that.
  776.             */
  777.  
  778.             strcpy(tmpfuncnam, functionp);
  779.             tmpfuncnam[fnlen-1] = '\0';
  780.  
  781.             functionp = tmpfuncnam;
  782.             loops     = 0;
  783.           }
  784.  
  785.           if(!loops)
  786.           {
  787.             if(mode & DEBUG) puts("Found via internal logic!");
  788.           }
  789.         }
  790.  
  791.         if(loops) for(i=0; p != NULL; i+=2)
  792.         {
  793.           if(!strcmp(p, functionp))
  794.           {
  795.             if(mode & DEBUG) puts("Found!");
  796.  
  797.             functionp = (char *) varargs[i - 1];        /* [i+1] */
  798.             loops = 0;
  799.             break;
  800.           }
  801.  
  802.           /*i += 2;*/
  803.           p = (char *) varargs[i];
  804.         }
  805.       }
  806.     }
  807.     offset += 6;
  808.  
  809.   } /* for(;;) */
  810.  
  811.   if(name) fclose(fd);
  812.  
  813.   fputs("\n\tend\n", lvos);
  814.  
  815.   fclose(lvos);
  816. }
  817.  
  818.  
  819. /*  Append '/' to path if needed
  820. */
  821.  
  822. static void fillpath(char *dirpath)
  823. {
  824.   int sl = strlen(dirpath);
  825.  
  826.   switch(dirpath[sl-1])
  827.   {
  828.     case ':':   /* ':' should be AMIGA-only! This will be commented out. */
  829.     case '/':
  830.       break;
  831.  
  832.     default:
  833.       strcpy(dirpath+sl, "/");
  834.       break;
  835.   }
  836. }
  837.  
  838.  
  839. /*  Show program usage
  840. */
  841.  
  842. static void Usage(const char *) NORETURN;
  843.  
  844. static void Usage(const char *myname)
  845. {
  846.   printf("fd2lib 1.5  (c) by Volker Barthelmann / "
  847.          "Johnny Teveßen / Frank Wille\n\n"
  848.          "  -- Caution: Needs ~5000 byte stack! --\n"
  849.          "\n"
  850.          "Usage : %s [-sc] [-sd] [-40] [-on] [-nv] [-o <dir>] [-of <format>]\n"
  851.          "           [-d] [-?|--help] [files/pattern]\n"
  852.          "\n"
  853.          "  -sc : Use small code model (else large code model)\n"
  854.          "  -sd : Use small data model (else large data model)\n"
  855.          "  -40 : Use fast call model for 68040\'s (no 'movem's)\n"
  856.          "  -on : Use old motorola assembler notation\n"
  857.          "  -nv : No varargs logic - ...A and ...TagList will not be detected\n"
  858.          "  -o  : Specify directory to store source files in\n"
  859.          "  -of : C printf style output format to generate compiling\n"
  860.          "        script. Three `%%s' are replaced with output file name\n"
  861.          "  -d  : Turn on debugging/verbose mode\n"
  862.          "  -?  : Show help/version and quit\n"
  863.          "files : FD files to convert, defaults to stdin\n"
  864.          "\n"
  865.          "Commandline is parsed left-to-right. Specifying\n"
  866.          "\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
  867.          "getting large data model.\n",
  868.          myname
  869.         );
  870.  
  871.   exit(0);
  872. }
  873.  
  874.  
  875. /*  Remember: ixemul.library does command line expansion, eg.:
  876. **
  877. **  redrose# fd2lib -sc -sd /fd/a*_lib.fd
  878. **
  879. **  will become:
  880. **
  881. **  redrose# fd2lib -sc -sd /fd/amigaguide_lib.fd /fd/asl_lib.fd ...
  882. **
  883. */
  884.  
  885. int main(int argc, char **argv)
  886. {
  887.   int erg       = 0 /*EXIT_FAILURE*/;
  888.   int mode      = NEWNOTATE | VARGSLOGIC;
  889.   int filesdone = 0;
  890.  
  891.   char outdir[80] = "", outform[250] = "";
  892.  
  893.   if(argc > 1)
  894.   {
  895.     int i;
  896.  
  897.     for(i=1; i<argc; i++)
  898.     {
  899.       if(argv[i][0] == '-')
  900.       {
  901.         /* Parse option */
  902.  
  903.              if( !strcmp(argv[i], "-sc")) mode |=  SMALLCODE;
  904.         else if( !strcmp(argv[i], "-sd")) mode |=  SMALLDATA;
  905.         else if( !strcmp(argv[i], "-40")) mode |=  FASTCALL;
  906.         else if( !strcmp(argv[i], "-on")) mode &= ~NEWNOTATE;
  907.         else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
  908.         else if( !strcmp(argv[i], "-pr")) clibname=argv[++i];
  909.         else if( !strcmp(argv[i], "-o" ))
  910.         {
  911.           if(i < (argc-1))
  912.           {
  913.             i ++;
  914.  
  915.             if(strlen(argv[i]) < sizeof(outdir))
  916.             {
  917.               strcpy  (outdir, argv[i]);
  918.               fillpath(outdir);
  919.             }
  920.             else
  921.             {
  922.               fprintf(stderr, "Path too long. Maximum is %lu characters. "
  923.                       "Ignored.\n", (unsigned long)sizeof(outdir));
  924.             }
  925.           }
  926.           else
  927.           {
  928.             fputs("No path specified after `-o'!\n", stderr);
  929.           }
  930.         }
  931.         else if( !strcmp(argv[i], "-of"))
  932.         {
  933.           if(i < (argc-1))
  934.           {
  935.             i ++;
  936.  
  937.             if(strlen(argv[i]) < sizeof(outform))
  938.             {
  939.               strcpy(outform, argv[i]);
  940.               strcat(outform, "\n"   );
  941.             }
  942.             else
  943.             {
  944.               fprintf(stderr, "Format too long. Maximum is %lu characters. "
  945.                       "Ignored.\n", (unsigned long)sizeof(outform));
  946.             }
  947.           }
  948.           else
  949.           {
  950.             fputs("No format specified after `-of'!\n", stderr);
  951.           }
  952.         }
  953.         else if( !strcmp(argv[i], "-d" )) mode |=  DEBUG;
  954.         else if((!strcmp(argv[i], "-?" )) ||
  955.                 (!strcmp(argv[i], "--help"))) Usage(*argv);
  956.         else
  957.         {
  958.           fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
  959.           Usage(*argv);
  960.         }
  961.       }
  962.       else
  963.       {
  964.         /* Process file */
  965.  
  966.         if(argv[i][0] == '?') Usage(*argv);
  967.         else
  968.         {
  969.           if(clibname){
  970.             FILE *file=fopen(clibname,"r");
  971.             size_t size;
  972.             if(!file){
  973.               fprintf(stderr, "Couldn't open <%s>!\n",clibname);
  974.               exit(EXIT_FAILURE);
  975.             }
  976.             if(fseek(file,0,SEEK_END)) exit(EXIT_FAILURE);
  977.             size=ftell(file);
  978.             if(fseek(file,0,SEEK_SET)) exit(EXIT_FAILURE);
  979.             clibtext=malloc(size+1);
  980.             if(!clibtext){
  981.               fprintf(stderr,"Out of memory!\n");
  982.               exit(EXIT_FAILURE);
  983.             }
  984.             clibtext[fread(clibtext,1,size,file)]=0;
  985.             fclose(file);
  986.           }
  987.           ProcessFD(argv[i], mode, outdir, outform);
  988.           if(clibname){
  989.             free(clibtext);
  990.             clibname=clibtext=0;
  991.           }
  992.           filesdone ++;
  993.         }
  994.       }
  995.     }
  996.   }
  997.  
  998.   if(!filesdone) ProcessFD(NULL, mode, outdir, outform);
  999.  
  1000.   return(erg);
  1001. }
  1002.